/*
 * Copyright (C) Francisco Morero Peyrona. All rights reserved.
 *
 * This software is published under the terms of Open Source
 * License version 1.1, a copy of which has been included with this
 * distribution in the License.txt file.
 */

package jdbcmanager.diagram.swing;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/**
 * A rectlangle that has a title header and the rest of its area can be
 * filled with Swing components.<br>
 * Can be selected or not (changeing its border and title color).
 * <p>
 * In fact, this is almost another implementation of JFrame.
 *
 * @author Francisco Morero Peyrona
 */

public class JBoard extends JPanel implements DiagramComponent
{
   public final static int nFRAME_BORDER_HEIGHT =  3;
   public final static int nFRAME_TITLE_HEIGHT  = 16;

   private static Color clrSelected   = new Color( 50,100,150 );
   private static Color clrUnSelected = Color.gray;

   private boolean bSelected = false;

   protected JRootPane  rootPane = new JRootPane();    // Placed at BorderLayout.CENTER
   protected TitlePane  title    = new TitlePane();    // Placed at BorderLayout.NORTH
   protected BottomEdge bottom   = new BottomEdge();   // Placed at BorderLayout.SOUTH
   
   //-------------------------------------------------------------------------//

   public JBoard()
   {
      this( null );
   }

   public JBoard( String sTitle )
   {
      setLayout( new BorderLayout() );      
      setTitle( sTitle );

      // Creates rootPane
      RootPaneMouseListener rpml = new RootPaneMouseListener(); 
      
      this.rootPane.getContentPane().setLayout( new BorderLayout() );
      this.rootPane.getGlassPane().addMouseListener( rpml );
      this.rootPane.getGlassPane().addMouseMotionListener( rpml );

      // Add title, rootPane and Bottom Border
      super.add( this.title   , BorderLayout.NORTH  );
      super.add( this.rootPane, BorderLayout.CENTER );
      super.add( this.bottom  , BorderLayout.SOUTH  );
      
      // Selects itself
      setSelected( true );
   }

   public Component add( Component c )
   {
      this.rootPane.getContentPane().add( c, BorderLayout.CENTER );
      return c; 
   }

   public String getTitle()
   {
      return this.title.getText();
   }

   public void setTitle( String sTitle )
   {
      this.title.setText( (sTitle == null) ? "" : sTitle.trim() );
   }

   public void setSelectedBackground( Color color )
   {
      if( color == null )
         color = new Color( 26, 93, 156 );
         
      clrSelected = color;

      if( isSelected() )
      {
         this.title.setBackground( color );
         setBorder( color );
      }
   }
   
   public void setUnselectedBackground( Color color )
   {
      if( color == null )
         color = new Color( 119, 136, 150 );
       
      clrUnSelected = color;

      if( ! isSelected() )
      {
         this.title.setBackground( color );
         setBorder( color );
      }
   }
   
   // NEXT: Add "setSelectedForeground" and "setUnselectedForegound"
    
   private void setBorder( Color color )
   {
      setBorder( BorderFactory.createMatteBorder( 0, JBoard.nFRAME_BORDER_HEIGHT, 0, JBoard.nFRAME_BORDER_HEIGHT, color ) );
      this.bottom.setBackground( color );      
   }

   public Dimension getMinimumSize() 
   {
      return new Dimension( 64, JBoard.nFRAME_TITLE_HEIGHT * 3 );
   }
   
   public Dimension getMaximumSize()
   {
      return new Dimension( 9999, 9999 );
   }
   
   public Dimension getPreferredSize()
   {
      return new Dimension( 280, 220 );
   }

   /**
    * To be redefined by sub-classes: called when double click on title bar
    */
   protected void toggleRestoreMaximize()
   {
   }
   
   //-------------------------------------------------------------------------//
   // REQUIRED BY DiagramComponent Interface

   public boolean isSelected()
   {
      return this.bSelected;
   }

   public void setSelected( boolean b )
   {
      if( this.bSelected != b )
      {         
         Color color = (b ? clrSelected : clrUnSelected );

         this.bSelected = b;
         this.rootPane.getGlassPane().setVisible( ! b );
         this.title.setBackground( color );
         setBorder( color );
      }
   }
   
   //-------------------------------------------------------------------------//
   // INNER CLASS: TITLE BORDER (with its mouse listener)
   //-------------------------------------------------------------------------//
   private final class TitlePane extends JLabel implements MouseInputListener
   {      
      private int nXMouseDisplacement;
      private int nYMouseDisplacement;

      private TitlePane()
      {
         setOpaque( true );
         setHorizontalAlignment( SwingConstants.CENTER );
         setForeground( Color.white );
         setFont( new Font( "Dialog", Font.BOLD, 10 ) );
         
         addMouseListener( this );
         addMouseMotionListener( this );
      }
      
      public Dimension getPreferredSize()
      {
         return new Dimension( JBoard.this.getWidth(), JBoard.nFRAME_TITLE_HEIGHT );
      }
      
      public void mouseClicked( MouseEvent evt )
      {
      }
      
      public void mouseEntered( MouseEvent evt )
      {
      }

      public void mouseExited( MouseEvent evt )
      {
      }     

      public void mousePressed( MouseEvent evt )
      {
         ((JDiagramPane) JBoard.this.getParent()).select( JBoard.this );
         
         if( evt.getButton() == MouseEvent.BUTTON1  )
         {
            this.nXMouseDisplacement = evt.getPoint().x;
            this.nYMouseDisplacement = evt.getPoint().y;            
         }
      }
      
      public void mouseReleased( MouseEvent evt )
      {
         if( evt.getClickCount() == 2 )
            toggleRestoreMaximize(); 
         
         ((JDiagramPane) JBoard.this.getParent()).resizeDesktop();
      }
      
      public void mouseDragged( MouseEvent evt )
      {
         JBoard.this.setLocation( evt.getPoint().x + JBoard.this.getX() - this.nXMouseDisplacement,
                                  evt.getPoint().y + JBoard.this.getY() - this.nYMouseDisplacement );
      }

      public void mouseMoved( MouseEvent evt )
      {
      }
   }
   
   //-------------------------------------------------------------------------//
   // INNER CLASS: BOTTOM BORDER (reasizability) (with its mouse listener)
   //-------------------------------------------------------------------------//
   private final class BottomEdge extends JPanel implements MouseInputListener 
   {
      private boolean bResizing = false;
      
      private BottomEdge()
      {
         setOpaque( true);
         setBackground( JBoard.clrSelected );     
         
         addMouseListener( this );
         addMouseMotionListener( this );    
      }

      public Dimension getPreferredSize()
      {
         return new Dimension( JBoard.this.getWidth(), JBoard.nFRAME_BORDER_HEIGHT );
      }
      
      public void mouseClicked( MouseEvent evt )
      {
      }

      public void mouseEntered( MouseEvent evt )
      {
         setCursor( Cursor.getPredefinedCursor( Cursor.S_RESIZE_CURSOR ) );
      }

      public void mouseExited( MouseEvent evt )
      {
         if( ! this.bResizing )
            setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
      }

      public void mousePressed( MouseEvent evt )
      {
         ((JDiagramPane) JBoard.this.getParent()).select( JBoard.this );
   
         if( evt.getButton() == MouseEvent.BUTTON1  )
            this.bResizing = true;
      }

      public void mouseReleased( MouseEvent evt )
      {
         this.bResizing = false;
         JBoard.this.revalidate();
         ((JDiagramPane) JBoard.this.getParent()).resizeDesktop();
      }

      public void mouseDragged( MouseEvent evt )
      {
         int nNewHeight = evt.getPoint().y + getY();
         
         if( nNewHeight > JBoard.this.getMinimumSize().height )
            JBoard.this.setSize( JBoard.this.getWidth(), nNewHeight );
      }

      public void mouseMoved( MouseEvent evt )
      {
      }
   }

   //-------------------------------------------------------------------------//
   // INNER CLASS: MOUSE LISTENER FOR RootPane
   //-------------------------------------------------------------------------//
   private final class RootPaneMouseListener extends MouseInputAdapter
   {
      public void mousePressed( MouseEvent evt )
      {
         ((JDiagramPane) getParent()).select( JBoard.this );    // All three mouse buttons select the JBoard
         
         // Redispatch mouse click          
         if( evt.getClickCount() == 1 && evt.getButton() == MouseEvent.BUTTON1 )
         {
            Point     glassPanePoint = evt.getPoint();
            Container container      = rootPane;
            Point     containerPoint = SwingUtilities.convertPoint( rootPane.getGlassPane(), glassPanePoint, container );
            Component component      = SwingUtilities.getDeepestComponentAt( container, containerPoint.x, containerPoint.y );
            
            if( component != null )
            {
               Point componentPoint = SwingUtilities.convertPoint( rootPane.getGlassPane(), glassPanePoint, component );
               
               component.dispatchEvent( new MouseEvent( component, evt.getID(), evt.getWhen(), evt.getModifiers(),
                                                        componentPoint.x, componentPoint.y, evt.getClickCount(), evt.isPopupTrigger() ) );
            }
         }
      }
   }
   //--------------------------------------------------------------------------//
}